/**
 * Copyright (c) 2012 Nokia Corporation.
 */

package com.nokia.example.imagescaler;

import javax.microedition.lcdui.Image;

/**
 * An image scaler using a bilinear interpolation algorithm.
 */
public final class BilinearInterpolationScaler extends ImageScaler {
	/**
	 * From ImageScaler.
	 */
	public Image scale(final int newWidth, final int newHeight, final Image originalImage) {
		if (newWidth <= 0 || newHeight <= 0) {
			throw new IllegalArgumentException(
					"Invalid scale new width or height! (" + newWidth + ", " + newHeight + ")");
		}
		if (originalImage == null) {
			throw new IllegalArgumentException(
					"Image to scale is null!");
		}
		
		// Get the size and the RGB array of the original image
		final int sourceWidth = originalImage.getWidth();
		final int sourceHeight = originalImage.getHeight();
		final int[] originalRgb = new int[sourceWidth * sourceHeight];
		originalImage.getRGB(originalRgb, 0, sourceWidth, 0, 0, sourceWidth, sourceHeight);
		
		final float xRatio = (float)(sourceWidth - 1) / newWidth;
		final float yRatio = (float)(sourceHeight - 1) / newHeight;
		final int[] scaledRgb = new int[newWidth * newHeight];
		int offset = 0;
		
		for (int i = 0; i < newHeight; ++i) {
			for (int j = 0; j < newWidth; ++j) {
				final int x = (int)(xRatio * j);
				final int y = (int)(yRatio * i);
				final float xDiff = xRatio * j - x;
				final float yDiff = yRatio * i - y;
				final int index = y * sourceWidth + x;

				final int a = originalRgb[index];
				final int b = originalRgb[index + 1];
				final int c = originalRgb[index + sourceWidth];
				final int d = originalRgb[index + sourceWidth + 1];
				
				final float alpha = ((a >> 24) & 0xff) * (1 - xDiff) * (1 - yDiff)
						+ ((b >> 24) & 0xff) * xDiff * (1-yDiff)
						+ ((c >> 24) & 0xff) * yDiff * (1-xDiff)
						+ ((d >> 24) & 0xff) * (xDiff * yDiff);
				
				final float red = ((a >> 16) & 0xff) * (1 - xDiff) * (1 - yDiff)
						+ ((b >> 16) & 0xff) * xDiff * (1-yDiff)
						+ ((c >> 16) & 0xff) * yDiff * (1-xDiff)
						+ ((d >> 16) & 0xff) * (xDiff * yDiff);
				
				final float green = ((a >> 8) & 0xff) * (1 - xDiff) * (1 - yDiff)
						+ ((b >> 8) & 0xff) * xDiff * (1 - yDiff)
						+ ((c >> 8) & 0xff) * yDiff * (1 - xDiff)
						+ ((d >> 8) & 0xff) * (xDiff * yDiff);
				
				final float blue = (a & 0xff) * (1 - xDiff) * (1 - yDiff)
						+ (b & 0xff) * xDiff * (1 - yDiff)
						+ (c & 0xff) * yDiff * (1 - xDiff)
						+ (d & 0xff) * (xDiff * yDiff);
				
				scaledRgb[offset++] = 
						((int)alpha << 24) & 0xff000000 |
						((int)red << 16) & 0xff0000 |
						((int)green << 8) & 0xff00 |
						(int)blue;
			}
		}
		
		return Image.createRGBImage(scaledRgb, newWidth, newHeight, true);
	}

	/**
	 * From ImageScaler.
	 */
	public String type() {
		return "Bilinear interpolation";
	}
}
